﻿using LightCAD.MathLib;
namespace QdArch
{
  
    public class QdWindow : LcComponent
    {
        public static Shape2dProvider ShapeProvider;
        public static ParameterSetDefinition ParamsDefinition;
        static QdWindow()
        {
            ShapeProvider = Shape2dManager.LoadProvider(ArchCategory.Window.ToString());

            ParamsDefinition = new ParameterSetDefinition() {
                 new ParameterDefinition
                 {
                     Name = "Thickness",
                     DataType= LcDataType.Double,
                 },
                 new ParameterDefinition
                 {
                     Name = "Width",
                      DataType= LcDataType.Double,
                 },
                 new ParameterDefinition
                 {
                     Name = "Height",
                     DataType= LcDataType.Double,
                 },
                 new ParameterDefinition
                 {
                     Name = "Bottom",
                     DataType= LcDataType.Double,
                 },
                 new ParameterDefinition
                 {
                     Name = "IsLeft",
                     DataType= LcDataType.Bool,
                 },
                 new ParameterDefinition
                 {
                     Name = "IsNear",
                     DataType= LcDataType.Bool,
                 },
            };

        }
        public QdWindow()
        {
            base.Category = ArchCategory.Window.ToString();
            this.Uuid = Guid.NewGuid().ToString();
        }
        public QdWindow(string subCategory, string name) : this()
        {
            base.SubCategory = subCategory;
            base.Name = name;
            this.Shape2D = ShapeProvider.Shapes.GetShape(name);
        }
    }

    public class QdWindowRef : LcComponentInstance, IElement3D
    {
        public object Rt3DAction { get; set; } = WindowAction3D.Instance;
        public LcParameterSet Parameters { get; set; }
        public QdWindow Window { get; set; }
        /// <summary>
        /// 在墙上用中心插入
        /// </summary>
        public QdWall Wall { get; set; }

        public Vector2 StartPoint { get; set; }
        public Vector2 EndPoint { get; set; }
        public Vector2 ControlPoint { get; set; }

        public double Thickness
        {
            get
            {
                return Convert.ToDouble(this.Parameters["Thickness"]);
            }
            set
            {
                this.Parameters["Thickness"] = value;
            }
        }
        public double Width
        {
            get
            {
                return Convert.ToDouble(this.Parameters["Width"]);
            }
            set
            {
                this.Parameters["Width"] = value;
            }
        }
        public double Height
        {
            get
            {
                return Convert.ToDouble(this.Parameters["Height"]);
            }
            set
            {
                this.Parameters["Height"] = value;
            }
        }
        public double Bottom
        {
            get
            {
                return Convert.ToDouble(this.Parameters["Bottom"]);
            }
            set
            {
                this.Parameters["Bottom"] = value;
            }
        }
        public bool IsLeft
        {
            get
            {
                return Convert.ToBoolean(this.Parameters["IsLeft"]);
            }
            set
            {
                this.Parameters["IsLeft"] = value;
            }
        }
        public bool IsNear
        {
            get
            {
                return Convert.ToBoolean(this.Parameters["IsNear"]);
            }
            set
            {
                this.Parameters["IsNear"] = value;
            }
        }

        public QdWindowRef()
        {
            this.Type = ArchElementType.Window;
        }

        public override Box2 GetBoundingBox()
        {
            if (this.Parameters == null || this.Parameters.Values.Length == 0)
            {
                return Box2.Empty;
            }

            return new Box2(this.InsertPoint, Width, Height);
        }

        public override bool IntersectWithBox(Polygon2d testPoly, List<RefChildElement> intersectChildren = null)
        {
            Box2 thisBox = this.BoundingBox;
            return thisBox.IntersectsBox(testPoly.BoundingBox);
        }

        public override bool IncludedByBox(Polygon2d testPoly, List<RefChildElement> includedChildren = null)
        {
            Box2 thisBox = this.BoundingBox;
            return thisBox.IntersectsBox(testPoly.BoundingBox);
        }

        public override void OnRemoveAfter()
        {
            this.Wall.RemoveLcComponent(this, "Window", AssociateType.Cross);
        }
        public override LcElement Clone()
        {
            var clone = Document.CreateObject<QdWindowRef>();
            clone.Copy(this);
            clone.Initilize(this.Document);
            return clone;
        }

        public override void Copy(LcElement src)
        {
            base.Copy(src);
            var winRef = (QdWindowRef)src;
            this.Parameters = winRef.Parameters;
            this.Window = winRef.Window;
            this.Wall = winRef.Wall;
            this.StartPoint = winRef.StartPoint;
            this.EndPoint = winRef.EndPoint;
            this.ControlPoint = winRef.ControlPoint;
            this.Width = winRef.Width;
            this.Height = winRef.Height;
            this.Bottom = winRef.Bottom;
            this.IsLeft = winRef.IsLeft;
            this.IsNear = winRef.IsNear;

        }

        public override void ReadObjectRefs<T>(ICollection<T> objs)
        {
            if (this.Wall != null)
            {
                var wallId = this.Wall.Id;
                this.Wall = objs.FirstOrDefault(o => o.Id == wallId) as QdWall;
            }
            if (this.Wall != null && this.Window != null)
            {
                this.Wall.AddLcComponent(this, "Window", AssociateType.Cross);
            }
        }
        public override void WriteProperties(Utf8JsonWriter writer, JsonSerializerOptions soptions)
        {
            base.WriteProperties(writer, soptions);

            writer.WriteStringProperty("WindowId", this.Window.Uuid);
            writer.WriteNumberProperty("WallId", this.Wall.Id);
            writer.WriteVector2dProperty(nameof(this.StartPoint), this.StartPoint);
            writer.WriteVector2dProperty(nameof(this.EndPoint), this.EndPoint);
            writer.WriteVector2dProperty(nameof(this.ControlPoint), this.ControlPoint);

            if (this.Thickness != 0)
            {
                writer.WriteNumberProperty(nameof(Thickness), this.Thickness);
            }
            if (this.Width != 0)
            {
                writer.WriteNumberProperty(nameof(Width), this.Width);
            }
            if (this.Height != 0)
            {
                writer.WriteNumberProperty(nameof(Height), this.Height);
            }
            if (this.Bottom != 0)
            {
                writer.WriteNumberProperty(nameof(Bottom), this.Bottom);
            }

            if (this.IsLeft)
            {
                writer.WriteBoolProperty(nameof(IsLeft), this.IsLeft);
            }

            if (this.IsNear)
            {
                writer.WriteBoolProperty(nameof(IsNear), this.IsNear);
            }

        }

        public override void ReadProperties(ref JsonElement jele)
        {
            base.ReadProperties(ref jele);

            var windowId = jele.ReadStringProperty("WindowId");
            var cpt = this.Document.Components[windowId];
            var window = new QdWindow(cpt.SubCategory, cpt.Name);
            window.Uuid = windowId;
            this.Window = window;
            this.Document.Components.Remove(windowId);
            this.Document.Components.Add(window);
            this.Wall = new QdWall()
            {
                Id = jele.ReadIdProperty("WallId")
            };
            this.Parameters = QdWindow.ParamsDefinition.New();
            this.StartPoint = jele.ReadVector2dProperty(nameof(this.StartPoint));
            this.EndPoint = jele.ReadVector2dProperty(nameof(this.EndPoint));
            this.ControlPoint = jele.ReadVector2dProperty(nameof(this.ControlPoint));
            this.Thickness = jele.ReadDoubleProperty(nameof(Thickness));
            this.Width = jele.ReadDoubleProperty(nameof(Width));
            this.Height = jele.ReadDoubleProperty(nameof(Height));
            this.Bottom = jele.ReadDoubleProperty(nameof(Bottom));
            this.IsLeft = jele.ReadBoolProperty(nameof(IsLeft)) ?? this.IsLeft;
            this.IsNear = jele.ReadBoolProperty(nameof(IsNear)) ?? this.IsNear;
        }
    }
}